package com.hex.ds.hdtp.core.inf.data.contrast.service.impl;

import cn.hutool.core.util.StrUtil;
import com.hex.bigdata.hbda.utils.StringUtils;
import com.hex.ds.hdtp.core.inf.common.exception.SourceJDBCException;
import com.hex.ds.hdtp.core.inf.common.utils.JdbcConnectUtil;
import com.hex.ds.hdtp.core.inf.common.utils.JdbcUtil;
import com.hex.ds.hdtp.core.inf.data.contrast.service.IDataInfoService;
import com.hex.ds.hdtp.core.inf.metadata.entity.TableFieldsEntity;
import com.hex.ds.hdtp.core.inf.metadata.po.SourceConfInfoPo;
import com.hex.ds.hdtp.core.inf.metadata.repository.ISourceConfInfoRepository;
import com.hex.ds.hdtp.core.inf.metadata.service.impl.SourceMethodHandlerContext;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@Slf4j
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public abstract class AbstractDataInfoService implements IDataInfoService {
    private final ISourceConfInfoRepository sourceConfInfoRepository;
    private final SourceMethodHandlerContext sourceMethodHandlerContext;


    /**
     * @Method selectTableExist
     * @Param
     * @Param sourceCode
     * @Param schema
     * @Param table
     * @Return java.lang.Boolean
     * @Description 是否有表
     * @Author xin.zhao
     * @Date 2023/9/1 15:29
     * @Version V1.0
     */
    @Override
    public Boolean selectTableExist(String sourceCode, String schema, String table) throws SQLException {
        List<SourceConfInfoPo> sourceConfInfoPoList = sourceConfInfoRepository.queryListBySourceCode(sourceCode);
        return JdbcConnectUtil.getTableExist(sourceConfInfoPoList, table);
    }

    /**
     * @Method selectAllFieldNum
     * @Param
     * @Param sourceCode
     * @Param schema
     * @Param table
     * @Return java.lang.Long
     * @Description 字段总数
     * @Author xin.zhao
     * @Date 2023/9/1 16:58
     * @Version V1.0
     */
    @Override
    public Long selectAllFieldNum(String sourceCode, String schema, String table) throws SQLException {
        List<SourceConfInfoPo> sourceConfInfoPoList = sourceConfInfoRepository.queryListBySourceCode(sourceCode);
        String querySql = sourceMethodHandlerContext.getSourceMethodService(sourceConfInfoPoList.get(0).getSourceType()).getTableAllFieldNumSql(schema, table);
        List<Map<String, Object>> tableInfo = JdbcConnectUtil.getListResult(sourceConfInfoPoList, querySql);
        return (long) tableInfo.size();
    }

    /**
     * @Method selectFieldName
     * @Param
     * @Param sourceCode
     * @Param schema
     * @Param table
     * @Return java.util.List<java.lang.String>
     * @Description 字段名称
     * @Author xin.zhao
     * @Date 2023/9/1 16:56
     * @Version V1.0
     */
    @Override
    public List<String> selectFieldName(String sourceCode, String schema, String table) {
        List<SourceConfInfoPo> sourceConfInfoPoList = sourceConfInfoRepository.queryListBySourceCode(sourceCode);
        String querySql = sourceMethodHandlerContext.getSourceMethodService(sourceConfInfoPoList.get(0).getSourceType()).getTableAllFieldNameSql(schema, table);
        try {
            return JdbcConnectUtil.getOneFieldResult(sourceConfInfoPoList, querySql);
        } catch (SQLException e) {
            throw new SourceJDBCException("字段名称获取失败", e);
        }
    }

    /**
     * @Method selectPartitionField
     * @Param
     * @Param sourceCode
     * @Param schema
     * @Param table
     * @Return java.util.List<java.lang.String>
     * @Description 查询分区字段
     * @Author xin.zhao
     * @Date 2023/11/29 10:24
     * @Version V1.0
     */
    @Override
    public List<String> selectPartitionField(String sourceCode, String schema, String table) throws SQLException {
        List<SourceConfInfoPo> sourceConfInfoPoList = sourceConfInfoRepository.queryListBySourceCode(sourceCode);
        String querySql = sourceMethodHandlerContext.getSourceMethodService(sourceConfInfoPoList.get(0).getSourceType()).getTablePartitionFieldSql(schema, table);
        return JdbcConnectUtil.getOneFieldResult(sourceConfInfoPoList, querySql);
    }

    /**
     * @Method selectCoding
     * @Param
     * @Param sourceCode
     * @Return java.lang.String
     * @Description 编码风格
     * @Author xin.zhao
     * @Date 2023/11/29 10:26
     * @Version V1.0
     */
    @Override
    public String selectCoding(String sourceCode) {
        log.error("暂不支持获取编码格式");
        throw new RuntimeException("暂不支持获取编码格式");
    }

    /**
     * @Method selectIsHaveData
     * @Param
     * @Param sourceCode
     * @Param schema
     * @Param table
     * @Return java.lang.Long
     * @Description 有无数据
     * @Author xin.zhao
     * @Date 2023/11/29 10:26
     * @Version V1.0
     */
    @Override
    public Long selectIsHaveData(String sourceCode, String schema, String table) throws SQLException {
        List<SourceConfInfoPo> sourceConfInfoPoList = sourceConfInfoRepository.queryListBySourceCode(sourceCode);
        String querySql = sourceMethodHandlerContext.getSourceMethodService(sourceConfInfoPoList.get(0).getSourceType()).getTableIsHaveDataSql(schema, table);
        return JdbcConnectUtil.getLongResult(sourceConfInfoPoList, querySql);
    }

    /**
     * @Method selectDataNum
     * @Param
     * @Param sourceCode
     * @Param schema
     * @Param table
     * @Return java.lang.Long
     * @Description 获取表的数据量
     * @Author xin.zhao
     * @Date 2023/9/1 18:02
     * @Version V1.0
     */
    @Override
    public Long selectDataNum(String sourceCode, String schema, String table, String partitionWhereSql, String whereCondition) throws SQLException {
        String whereSql = getWhereSql(partitionWhereSql, whereCondition);
        List<SourceConfInfoPo> sourceConfInfoPoList = sourceConfInfoRepository.queryListBySourceCode(sourceCode);
        String querySql = selectDataNumSql(schema, table, whereSql);
        return JdbcConnectUtil.getLongResult(sourceConfInfoPoList, querySql);
    }

    /**
     * @Method selectLengthMax
     * @Param
     * @Param sourceCode
     * @Param schema
     * @Param table
     * @Param field
     * @Param partitionWhereSql
     * @Return java.lang.Long
     * @Description 字段最大长度
     * @Author xin.zhao
     * @Date 2023/11/29 10:29
     * @Version V1.0
     */
    @Override
    public Long selectLengthMax(String sourceCode, String schema, String table, String field, String partitionWhereSql) throws SQLException {
        List<SourceConfInfoPo> sourceConfInfoPoList = sourceConfInfoRepository.queryListBySourceCode(sourceCode);
        String querySql = sourceMethodHandlerContext.getSourceMethodService(sourceConfInfoPoList.get(0).getSourceType()).getTableLengthMaxSql(field, schema, table, partitionWhereSql);
        return JdbcConnectUtil.getLongResult(sourceConfInfoPoList, querySql);
    }

    /**
     * @Method selectFieldLengthSum
     * @Param
     * @Param sourceCode
     * @Param field
     * @Param schema
     * @Param table
     * @Param partitionWhereSql
     * @Return java.lang.Long
     * @Description 指定字段字段 长度sum
     * @Author xin.zhao
     * @Date 2023/11/29 10:31
     * @Version V1.0
     */
    @Override
    public Long selectFieldLengthSum(String sourceCode, String field, String schema, String table, String partitionWhereSql) throws SQLException {
        List<SourceConfInfoPo> sourceConfInfoPoList = sourceConfInfoRepository.queryListBySourceCode(sourceCode);
        String querySql = sourceMethodHandlerContext.getSourceMethodService(sourceConfInfoPoList.get(0).getSourceType()).getTableFieldLengthSumSql(field, schema, table, partitionWhereSql);
        return JdbcConnectUtil.getLongResult(sourceConfInfoPoList, querySql);
    }

    /**
     * @Method selectFieldLengthSumTrim
     * @Param
     * @Param sourceCode
     * @Param field
     * @Param schema
     * @Param table
     * @Param partitionWhereSql
     * @Return java.lang.Long
     * @Description 指定字段 长度 trim sum
     * @Author xin.zhao
     * @Date 2023/11/29 10:33
     * @Version V1.0
     */
    @Override
    public Long selectFieldLengthSumTrim(String sourceCode, String field, String schema, String table, String partitionWhereSql) throws SQLException {
        List<SourceConfInfoPo> sourceConfInfoPoList = sourceConfInfoRepository.queryListBySourceCode(sourceCode);
        String querySql = sourceMethodHandlerContext.getSourceMethodService(sourceConfInfoPoList.get(0).getSourceType()).getTableFieldLengthSumTrimSql(field, schema, table, partitionWhereSql);
        return JdbcConnectUtil.getLongResult(sourceConfInfoPoList, querySql);
    }

    /**
     * @Method fieldNumberSum
     * @Param
     * @Param sourceCode
     * @Param field
     * @Param schema
     * @Param table
     * @Param partitionWhereSql
     * @Return java.lang.Float
     * @Description 数字类型 sum
     * @Author xin.zhao
     * @Date 2023/11/29 10:38
     * @Version V1.0
     */
    @Override
    public Float fieldNumberSum(String sourceCode, String field, String schema, String table, String partitionWhereSql) throws SQLException {
        List<SourceConfInfoPo> sourceConfInfoPoList = sourceConfInfoRepository.queryListBySourceCode(sourceCode);
        String querySql = sourceMethodHandlerContext.getSourceMethodService(sourceConfInfoPoList.get(0).getSourceType()).getTableFieldSumSql(field, schema, table, partitionWhereSql);
        String stringResult = JdbcConnectUtil.getStringResult(sourceConfInfoPoList, querySql);
        if (StringUtils.isBlank(stringResult)) {
            return null;
        }
        return Float.valueOf(stringResult);
    }


    /**
     * @Method selectDistinctCount
     * @Param
     * @Param sourceCode
     * @Param schema
     * @Param table
     * @Param field
     * @Return java.lang.Long
     * @Description 去重Count
     * @Author xin.zhao
     * @Date 2023/9/1 18:05
     * @Version V1.0
     */
    @Override
    public Long selectDistinctCount(String sourceCode, String schema, String table, String field, String whereSql) throws SQLException {
        List<SourceConfInfoPo> sourceConfInfoPoList = sourceConfInfoRepository.queryListBySourceCode(sourceCode);
        String querySql = sourceMethodHandlerContext.getSourceMethodService(sourceConfInfoPoList.get(0).getSourceType()).getTableDistinctCountSql(field, schema, table, whereSql);
        return JdbcConnectUtil.getLongResult(sourceConfInfoPoList, querySql);
    }

    /**
     * @Method selectCountSumIsNull
     * @Param
     * @Param sourceCode
     * @Param schema
     * @Param table
     * @Param field
     * @Return java.lang.Long
     * @Description 字段为空总数
     * @Author xin.zhao
     * @Date 2023/11/29 10:40
     * @Version V1.0
     */
    @Override
    public Long selectCountSumIsNull(String sourceCode, String schema, String table, String field, String whereSql) throws SQLException {
        List<SourceConfInfoPo> sourceConfInfoPoList = sourceConfInfoRepository.queryListBySourceCode(sourceCode);
        String querySql = selectCountSumIsNullSql(schema, table, field, whereSql);
        return JdbcConnectUtil.getLongResult(sourceConfInfoPoList, querySql);
    }

    /**
     * @Method selectGroupCount
     * @Param
     * @Param sourceCode
     * @Param schema
     * @Param table
     * @Param field
     * @Return java.lang.Long
     * @Description 分组Count
     * @Author xin.zhao
     * @Date 2023/9/1 18:13
     * @Version V1.0
     */
    @Override
    public Long selectGroupCount(String sourceCode, String schema, String table, String field, String whereSql) throws SQLException {
        List<SourceConfInfoPo> sourceConfInfoPoList = sourceConfInfoRepository.queryListBySourceCode(sourceCode);
        String querySql = sourceMethodHandlerContext.getSourceMethodService(sourceConfInfoPoList.get(0).getSourceType()).getTableGroupCountSql(schema, table, field, whereSql);
        return JdbcConnectUtil.getLongResult(sourceConfInfoPoList, querySql);
    }

    /**
     * @Method getJdbcListStringResult
     * @Param sourceCode
     * @Param querySql
     * @Return java.util.List<java.util.Map < java.lang.String, java.lang.String>>
     * @Description 返回执行结果
     * @Author gj.xu
     * @Date 2024/1/25 18:52
     * @Version V2.0
     */
    private List<Map<String, String>> getJdbcListStringResult(String sourceCode, String querySql) throws SQLException {
        Map<String, String> sourceConfInfo = getSourceConfInfo(sourceCode);
        return JdbcConnectUtil.getJdbcListStringResult(sourceConfInfo.get("driverClassName"), sourceConfInfo.get("url"), sourceConfInfo.get("username"), sourceConfInfo.get("password"), querySql);
    }

    /**
     * @Method selectFieldCount
     * @Param
     * @Param sourceCode
     * @Param schema
     * @Param table
     * @Param field
     * @Return java.lang.Long
     * @Description 字段Count
     * @Author xin.zhao
     * @Date 2023/9/1 18:14
     * @Version V1.0
     */
    @Override
    public List<Map<String, String>> selectFieldCount(String sourceCode, String schema, String table, String field, String whereSql) throws SQLException {
        List<SourceConfInfoPo> sourceConfInfoPoList = sourceConfInfoRepository.queryListBySourceCode(sourceCode);
        String querySql = sourceMethodHandlerContext.getSourceMethodService(sourceConfInfoPoList.get(0).getSourceType()).getTableFieldGroupCountSql(schema, table, field, whereSql);
        return getJdbcListStringResult(sourceCode, querySql);

    }


    /**
     * @Method selectFieldSum
     * @Param
     * @Param sourceCode
     * @Param schema
     * @Param table
     * @Param field
     * @Return java.lang.Long
     * @Description 字段Sum
     * @Author xin.zhao
     * @Date 2023/9/4 11:05
     * @Version V1.0
     */
    @Override
    public Long selectFieldSum(String sourceCode, String schema, String table, String field, String whereSql) throws SQLException {
        List<SourceConfInfoPo> sourceConfInfoPoList = sourceConfInfoRepository.queryListBySourceCode(sourceCode);
        String querySql = sourceMethodHandlerContext.getSourceMethodService(sourceConfInfoPoList.get(0).getSourceType()).getTableFieldSumSql(field, schema, table, whereSql);
        return JdbcConnectUtil.getLongResult(sourceConfInfoPoList, querySql);
    }

    /**
     * @Method selectFieldTrim
     * @Param
     * @Param sourceCode
     * @Param schema
     * @Param table
     * @Param field
     * @Return java.util.List<java.lang.String>
     * @Description 字段Trim
     * @Author xin.zhao
     * @Date 2023/9/4 11:03
     * @Version V1.0
     */
    @Override
    public List<String> selectFieldTrim(String sourceCode, String schema, String table, String field, String whereSql) throws SQLException {
        List<SourceConfInfoPo> sourceConfInfoPoList = sourceConfInfoRepository.queryListBySourceCode(sourceCode);
        String querySql = sourceMethodHandlerContext.getSourceMethodService(sourceConfInfoPoList.get(0).getSourceType()).getTableFieldTrimSql(field, schema, table, whereSql);
        return JdbcConnectUtil.getOneFieldResult(sourceConfInfoPoList, querySql);
    }


    /**
     * @Method selectCustomSql
     * @Param
     * @Param dataInfoPo
     * @Return java.util.List<java.util.Map < java.lang.String, java.lang.Object>>
     * @Description 自定义Sql
     * @Author xin.zhao
     * @Date 2023/9/4 9:48
     * @Version V1.0
     */
    @Override
    public List<Map<String, Object>> selectCustomSql(String sourceCode, String customSql) throws SQLException {
        Map<String, String> sourceConfInfo = getSourceConfInfo(sourceCode);
        return JdbcConnectUtil.getJdbcListResult(sourceConfInfo.get("driverClassName"), sourceConfInfo.get("url"), sourceConfInfo.get("username"), sourceConfInfo.get("password"), customSql);
    }

    /**
     * @Method selectAllFieldSql
     * @Param
     * @Param fields
     * @Param schema
     * @Param table
     * @Return java.lang.String
     * @Description 获取全字段明细对比的SQL
     * @Author xin.zhao
     * @Date 2023/9/4 9:40
     * @Version V1.0
     */
    @Override
    public String selectAllFieldSql(String sourceType, String fields, String schema, String table, String partitionsWhereSql, String sortField) {
        return sourceMethodHandlerContext.getSourceMethodService(sourceType).getTableAllFieldSql(fields, schema, table, partitionsWhereSql, sortField);
    }

    /**
     * @Method selectAllFieldSql
     * @Param
     * @Param fields
     * @Param schema
     * @Param table
     * @Return java.lang.String
     * @Description 获取分批比对全字段明细对比的SQL
     * @Author xin.zhao
     * @Date 2023/9/4 9:40
     * @Version V1.0
     */
    @Override
    public String selectAllFieldSqlLimit(String sourceType, String fields, String schema, String table, String partitionsWhereSql, Long extractScope, Long offset, String sortField) {
        return sourceMethodHandlerContext.getSourceMethodService(sourceType).getTableAllFieldSqlLimitSql(fields, schema, table, partitionsWhereSql, extractScope, offset, sortField);
    }

    /**
     * @Method selectCreateTableSql
     * @Param
     * @Param sourceCode
     * @Param schema
     * @Param table
     * @Return java.lang.String
     * @Description 查询表的建表语句
     * @Author xin.zhao
     * @Date 2023/9/6 14:08
     * @Version V1.0
     */
    @Override
    public String selectCreateTableSql(String sourceCode, String schema, String table) {
        String stringResult = null;
        try {
            List<SourceConfInfoPo> sourceConfInfoPoList = sourceConfInfoRepository.queryListBySourceCode(sourceCode);
            String querySql = sourceMethodHandlerContext.getSourceMethodService(sourceConfInfoPoList.get(0).getSourceType()).getTableShowCreateTableSql(schema, table);
            stringResult = JdbcConnectUtil.getStringResult(sourceConfInfoPoList, querySql);
        } catch (Exception e) {
            log.error("获取建表语句异常: {}", e.getMessage(), e);
        }
        return stringResult;
    }

    @Override
    public String buildCreateTableSql(List<TableFieldsEntity> tableFieldsEntities, List<String> partitionFieldName, String isCover) {
        log.error("暂未支持生成建表语句");
        throw new RuntimeException("暂未支持生成建表语句");
    }

    /**
     * @Method selectAllFieldType
     * @Param
     * @Param sourceCode
     * @Param schema
     * @Param table
     * @Return java.util.List<java.util.Map < java.lang.String, java.lang.String>>
     * @Description 字段类型
     * @Author xin.zhao
     * @Date 2023/11/29 15:26
     * @Version V1.0
     */
    @Override
    public List<Map<String, String>> selectAllFieldType(String sourceCode, String schema, String table) throws SQLException {
        List<SourceConfInfoPo> sourceConfInfoPoList = sourceConfInfoRepository.queryListBySourceCode(sourceCode);
        String querySql = sourceMethodHandlerContext.getSourceMethodService(sourceConfInfoPoList.get(0).getSourceType()).getTableAllFieldTypeSql(schema, table);
        return getJdbcListStringResult(sourceCode, querySql);
    }

    /**
     * @Method selectAllFieldLength
     * @Param
     * @Param sourceCode
     * @Param schema
     * @Param table
     * @Return java.util.List<java.util.Map < java.lang.String, java.lang.String>>
     * @Description 字段长度
     * @Author xin.zhao
     * @Date 2023/11/29 15:27
     * @Version V1.0
     */
    @Override
    public List<Map<String, String>> selectAllFieldLength(String sourceCode, String schema, String table) throws SQLException {
        List<SourceConfInfoPo> sourceConfInfoPoList = sourceConfInfoRepository.queryListBySourceCode(sourceCode);
        String querySql = sourceMethodHandlerContext.getSourceMethodService(sourceConfInfoPoList.get(0).getSourceType()).getTableAllFieldLengthSql(schema, table);
        return getJdbcListStringResult(sourceCode, querySql);
    }

    /**
     * @Method selectFieldAccuracy
     * @Param
     * @Param sourceCode
     * @Param schema
     * @Param table
     * @Return java.util.List<java.util.Map < java.lang.String, java.lang.String>>
     * @Description 字段精度
     * @Author xin.zhao
     * @Date 2023/11/29 15:27
     * @Version V1.0
     */
    @Override
    public List<Map<String, String>> selectFieldAccuracy(String sourceCode, String schema, String table) throws SQLException {
        List<SourceConfInfoPo> sourceConfInfoPoList = sourceConfInfoRepository.queryListBySourceCode(sourceCode);
        String querySql = sourceMethodHandlerContext.getSourceMethodService(sourceConfInfoPoList.get(0).getSourceType()).getTableFieldAccuracySql(schema, table);
        return getJdbcListStringResult(sourceCode, querySql);

    }

    public Map<String, String> getSourceConfInfo(String sourceCode) {
        List<SourceConfInfoPo> sourceConfInfoPoList = sourceConfInfoRepository.queryListBySourceCode(sourceCode);
        sourceConfInfoPoList = sourceConfInfoPoList.stream().filter(sourceConf -> StrUtil.isNotBlank(sourceConf.getConfValue())).collect(Collectors.toList());
        Map<String, String> sourceConfInfo = sourceConfInfoPoList.stream().collect(Collectors.toMap(SourceConfInfoPo::getConfName, SourceConfInfoPo::getConfValue));
        sourceConfInfo.put("sourceType", sourceConfInfoPoList.get(0).getSourceType());
        String jdbcUrl = JdbcUtil.getJDBCUrl(sourceConfInfo);
        sourceConfInfo.put("url", jdbcUrl);
        return sourceConfInfo;
    }


    protected abstract String selectDataNumSql(String schema, String table, String whereSql);

    protected abstract String selectCountSumIsNullSql(String schema, String table, String field, String whereSql);

    protected ISourceConfInfoRepository getSourceConfInfoRepository() {
        return sourceConfInfoRepository;
    }

    protected SourceMethodHandlerContext getSourceMethodHandlerContext() {
        return sourceMethodHandlerContext;
    }

    protected String getWhereSql(String partitionWhereSql, String whereCondition) {
        if (StringUtils.isNotBlank(partitionWhereSql)) {
            if (StringUtils.isNotBlank(whereCondition)) {
                return partitionWhereSql + " and " + whereCondition;
            } else {
                return partitionWhereSql;
            }
        } else {
            if (StringUtils.isNotBlank(whereCondition)) {
                return "where " + whereCondition;
            } else {
                return "";
            }
        }
    }

    /**
     * @Method getStrDataType
     * @Param sourceType
     * @Return java.util.List<java.lang.String>
     * @Description 获取字符数据类型
     * @Author gj.xu
     * @Date 2024/2/21 13:11
     * @Version V2.0
     */
    @Override
    public List<String> getStrDataType(String sourceType) {
        return sourceMethodHandlerContext.getSourceMethodService(sourceType).getStrDataType();
    }

    /**
     * @Method getNumDataType
     * @Param sourceType
     * @Return java.util.List<java.lang.String>
     * @Description 获取数值数据类型
     * @Author gj.xu
     * @Date 2024/2/21 15:22
     * @Version V2.0
     */
    @Override
    public List<String> getNumDataType(String sourceType) {
        return sourceMethodHandlerContext.getSourceMethodService(sourceType).getNumDataType();
    }

    /**
     * @Method getAccuracyDataType
     * @Param sourceType
     * @Return java.util.List<java.lang.String>
     * @Description 获取精度数据类型
     * @Author gj.xu
     * @Date 2024/2/21 15:30
     * @Version V2.0
     */
    @Override
    public List<String> getAccuracyDataType(String sourceType) {
        return sourceMethodHandlerContext.getSourceMethodService(sourceType).getAccuracyDataType();
    }
}
